/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.model;

import com.vividsolutions.jts.geom.Geometry;
import java.awt.datatransfer.DataFlavor;
import java.util.Date;
import javax.jdo.annotations.Index;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import nl.cloudfarming.client.logging.AppLogFactory;
import nl.cloudfarming.client.logging.AppLogger;
import nl.cloudfarming.client.util.GeometryUtil;

/**
 * base class for surfaces
 *
 * @author Timon Veenstra
 */
@MappedSuperclass
public abstract class Surface extends Bean {
    //
    // data flavor for drag and drop support of layers
    //
    public static final DataFlavor DATA_FLAVOR = new DataFlavor(Surface.class, "surface");        

    @Column
    private Double acreage;
    @Column
    private String code;
    @Column
    @Index
    @Temporal(TemporalType.DATE)
    private Date startDate;
    @Column
    @Index
    @Temporal(TemporalType.DATE)
    private Date endDate;
    @Column(name = "WKT", length = 10000)
    private String WKT;
    private static final AppLogger LOG = AppLogFactory.getLogger(Surface.class);


    public Double getAcreage() {
        return acreage;
    }

    public void setAcreage(Double acreage) {
        Double old = this.acreage;
        this.acreage = acreage;
        getPropertyChangeSupport().firePropertyChange("acreage", old, acreage);
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        String old = this.code;
        this.code = code;
        getPropertyChangeSupport().firePropertyChange("code", old, code);
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        if (endDate == null || (startDate == null || endDate.compareTo(startDate) > 0)) {
            Date old = this.endDate;
            this.endDate = endDate;
            getPropertyChangeSupport().firePropertyChange("endDate", old, endDate);
            fireUndoableEvent("endDate", this, old, endDate);
        } else {
            // Todo: temp debug, should display in message window
            LOG.warning("surface.setenddate");
            // http://netbeans.org/bugzilla/show_bug.cgi?id=188880
            //throw new DateSetException("Enddate should be > startdate");
        }
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        if (startDate == null || (endDate == null || startDate.compareTo(endDate) < 0)) {
            Date old = this.startDate;
            this.startDate = startDate;
            getPropertyChangeSupport().firePropertyChange("startDate", old, startDate);
            fireUndoableEvent("startDate", this, old, startDate);
        } else {
            LOG.warning("surface.setstartdate");
            // http://netbeans.org/bugzilla/show_bug.cgi?id=188880
            //throw new DateSetException("Startdate should be < enddate");
        }
    }

    public String getWKT() {
        return WKT;
    }

    public void setWKT(String WKT) {
        String old = this.WKT;
        this.WKT = WKT;
        getPropertyChangeSupport().firePropertyChange("WKT", old, WKT);
    }
    
    public Geometry getGeometry(){
        return GeometryUtil.wktToGeometry(getWKT());
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        if(!super.equals(obj)){
            return false;
        } 
        final Surface other = (Surface) obj;
        if (this.acreage != other.acreage && (this.acreage == null || !this.acreage.equals(other.acreage))) {
            return false;
        }
        if ((this.code == null) ? (other.code != null) : !this.code.equals(other.code)) {
            return false;
        }
        if (this.startDate != other.startDate && (this.startDate == null || !this.startDate.equals(other.startDate))) {
            return false;
        }
        if (this.endDate != other.endDate && (this.endDate == null || !this.endDate.equals(other.endDate))) {
            return false;
        }
        if ((this.WKT == null) ? (other.WKT != null) : !this.WKT.equals(other.WKT)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 31 * hash + (this.acreage != null ? this.acreage.hashCode() : 0);
        hash = 31 * hash + (this.code != null ? this.code.hashCode() : 0);
        hash = 31 * hash + (this.startDate != null ? this.startDate.hashCode() : 0);
        hash = 31 * hash + (this.endDate != null ? this.endDate.hashCode() : 0);
        hash = 31 * hash + (this.WKT != null ? this.WKT.hashCode() : 0);
        return hash;
    }

    public static abstract class Builder<S extends Surface> {

        private final S surface;

        public Builder(S surface) {
            this.surface = surface;
        }

        public S getSurface() {
            return surface;
        }

        public Builder setWKT(String WKT) {
            surface.setWKT(WKT);
            return this;
        }

        public Builder setAcreage(Double acreage) {
            surface.setAcreage(acreage);
            return this;
        }

        public Builder setCode(String code) {
            surface.setCode(code);
            return this;
        }

        public Builder setName(String name) {
            surface.setName(name);
            return this;
        }

        public Builder setEndDate(Date endDate) {
            surface.setEndDate(endDate);
            return this;
        }

        public Builder setStartDate(Date startDate) {
            surface.setStartDate(startDate);
            return this;
        }

        public abstract S build();
    }
}
